// 简单发布订阅模式
class EventBus {
  constructor() {
    this.task = {};
  }

  // 绑定事件 将cb push到任务队列（即订阅）
  on(name, cb) {
    if (!this.task[name]) {
      this.task[name] = [];
    }

    typeof cb === 'function' && this.task[name].push(cb);
  }

  // 触发事件 拿到当前任务队列，遍历执行（即发布）
  emit(name, ...args) {
    let taskQueue = this.task[name];
    if (taskQueue && taskQueue.length > 0) {
      taskQueue.map((cb) => cb(...args));
    }
  }

  // 解除事件绑定 从当前事件队列移除当前事件 即数组删除当前元素（即取消订阅）
  off(name, cb) {
    let taskQueue = this.task[name];
    if (taskQueue && taskQueue.length > 0) {
      let idx = taskQueue.indexOf(cb);
      idx !== -1 && taskQueue.splice(idx, 1);
    }

    if (typeof cb === 'undefined') {
      this.task[name].length = 0;
    }
  }

  // 一次事件 先移除当前事件，在绑定（即订阅一次）
  once(name, cb) {
    let callback = (...args) => {
      this.off(name, callback);
      cb(...args);
    };

    typeof cb === 'function' && this.on(name, callback);
  }

  // 解除所有事件绑定（即取消所有订阅）
  offAllListener(name) {
    if (this.task[name]) {
      delete this.task[name];
    }
  }
}

let bus = new EventBus();
bus.on('add', function (a, b) {
  console.log(a + b);
});
bus.emit('add', 10, 20);

let obj = {
  list: [], // 可以用对象，这里用数组代替
  // 订阅
  listener: function (key, fn) {
    this.list[key] = [...(this.list[key] || []), fn];
  },
  //发布
  trigger: function () {
    let [key, ...args] = [...arguments];

    let listFns = this.list[key];
    if (listFns.length == 0 || !listFns) {
      return;
    }

    for (let itemFn of listFns) {
      itemFn.apply(this, args);
    }
  },
};

obj.listener('eat', (food) => {
  console.log(`晚上吃的是${food}`);
});
obj.listener('drink', (water) => {
  console.log(`晚上喝的是${water}`);
});
obj.trigger('eat', '面条');
obj.trigger('drink', '椰子水');
